<?php
#http://us.battle.net/d3/en/forum/topic/8796681164
#http://blizzard.github.io/d3-api-docs/

#$url = 'http://eu.battle.net/api/d3/profile/Astaltar-2844';

class Parser
{
    const API_URL = 'http://{realm}.battle.net/api/d3/profile/{battleTag}-{battleTagId}/';
    const API_URL_HERO = 'http://{realm}.battle.net/api/d3/profile/{battleTag}-{battleTagId}/hero/{heroId}';
    const API_URL_ITEM = 'http://{realm}.battle.net/api/d3/data/{data}';
    protected $_realms = array('eu', 'us');
    protected $TTL = 86400; // 24 hours

    protected $_realm;
    protected $_battleTag;
    protected $_battleTagId;
    protected $_heroId;
    protected $_itemId;

    const TYPE_PROFILE = 'profile';
    const TYPE_HERO = 'hero';
    const TYPE_ITEM = 'item';

    public function __construct($realm, $battleTag)
    {
        $this->_realm = $realm;
        $p = explode('#', $battleTag);
        if (count($p) != 2 || !is_numeric($p[1])) {
            throw new Exception('BattleTag "'.$battleTag.'" is not valid');
        }

        $this->_battleTag = trim($p[0]);
        $this->_battleTagId = trim($p[1]);
    }

    public function load($type = self::TYPE_PROFILE, $extraId = false)
    {
        switch ($type) {
            case self::TYPE_ITEM : $this->_itemId = $extraId;
                break;
            case self::TYPE_HERO : $this->_heroId = $extraId;
                break;
        }

        $data = $this->_loadFromCache($type);
        if ($data === false) {
            $ret = $this->_loadFromApi($type);
            if (!empty($ret['data'])) {
                $data = $ret['data'];
                $this->_saveToCache($ret['data'], $type);
            }
        }

        return $data;
    }

    protected function _getCacheFile($type)
    {
        $parts = array(
            $this->_realm,
            $type
        );

        if ($type == self::TYPE_ITEM) {
            $parts[] = $this->_itemId;
        } else {
            $parts = array(
                $this->_realm,
                $this->_battleTag,
                $this->_battleTagId
            );
        }

        if ($type == self::TYPE_HERO) {
            $parts[] = $this->_heroId;
        }

        $fileMD5 = md5(strtolower(join('/', $parts)));
        return DIR_CACHE.'/armoryCache/'.substr($fileMD5, 0, 3).'/'.substr($fileMD5, 3).'.sdata';
    }

    protected function _loadFromCache($type)
    {
        $file = $this->_getCacheFile($type);
        if (!file_exists($file)) {
            return false;
        }

        $data = unserialize(file_get_contents($file));
        if (time() - $data['stored'] > $this->TTL) {
            unlink($file);
            return false;
        }
        return $data['data'];
    }

    protected function _saveToCache($data, $type)
    {
        $data = array(
            'data'  => $data,
            'stored'=> time(),
        );
        $file = $this->_getCacheFile($type);
        make_all_dirs($file, true);
        umask(0);
        $f = fopen($file, 'w');

        fwrite($f, serialize($data));
        fclose($f);
    }

    protected function _buildUrl($type)
    {
        switch ($type) {
            case self::TYPE_PROFILE : $url = self::API_URL;
                break;
            case self::TYPE_HERO : $url = self::API_URL_HERO;
                break;
            case self::TYPE_ITEM: $url = self::API_URL_ITEM;
                break;
            default: throw new Exception('Invalid type "'.$type.'"');
                break;
        }

        return str_replace(
            array(
                '{realm}',
                '{battleTag}',
                '{battleTagId}',
                '{heroId}',
                '{data}',
            ),
            array(
                $this->_realm,
                $this->_battleTag,
                $this->_battleTagId,
                $this->_heroId,
                $this->_itemId,
            ),
            $url
        );
    }

    protected function _loadFromApi($type)
    {
        $url = $this->_buildUrl($type);
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (MSIE 6.0; Windows NT 5.0)');
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_TIMEOUT_MS, 2000);
        $response = curl_exec($ch);
        $error = curl_error($ch);
        $errno = curl_errno($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        return array(
            'error' => $error,
            'errno' => $errno,
            'body'  => $response,
            'code'  => $code,
            'data'  => (!$errno && $code == 200) ? json_decode($response, true) : false
        );
    }
}